# coding: utf-8

# -------------------------------------------------------------------------------
# Name:         extractor.py
# Description:  提取器
# Author:       XiangjunZhao
# EMAIL:        2419352654@qq.com
# Date:         2020/2/25 16:48
# -------------------------------------------------------------------------------
import json
import logging
import re

import jsonpath

logger = logging.getLogger(__name__)


class Extractor(object):
    """
    提取器
    主要功能：
        1、从响应中提取需要输出的变量信息并返回
    """

    @classmethod
    def extract_value(cls, resp_obj=None, variable_list=None):
        """
        从接口返回中提取变量的值
        Args:
            resp_obj: ResponseObject对象实例
            variable_list:


        Returns: result_dict 从resp_obj中提取后的mapping

        """
        if variable_list is None:
            variable_list = list()

        result_dict = {}
        for variable in variable_list:
            # 取值来源
            source = variable.get('source', 'results')
            # 存储变量名
            variable_name = variable.get('variable_name')
            # 取值方式
            extractor = variable.get('extractor', 'JSONPATH')
            # 取值表达式
            expression = variable.get('expression')
            # 取值数据类型
            # output_value_type = variable.get('output_value_type')
            variable_value = None
            if source in ['status_code', 'elapsed', 'url']:
                variable_value = resp_obj.get(source)
            else:
                obj = resp_obj.get(source)
                if extractor == 'JSONPATH':
                    variable_value = cls.extract_value_by_jsonpath(obj=obj, expr=expression)
                elif extractor == 'REGEXP':
                    if not isinstance(obj, str):
                        obj = json.dumps(obj, ensure_ascii=False)
                    variable_value = cls.extract_value_by_regexp(obj=obj, expr=expression)
            cls.update_result_dict(extractor, variable_name, variable_value, result_dict)
        return result_dict

    @staticmethod
    def extract_value_by_jsonpath(obj=None, expr: str = None):
        """
        根据jsonpath从obj中提取相应的值
        Args:
            obj:
            expr: jsonpath表达式

        Returns:

        """
        logger.info('正在执行数据提取：JsonPath提取表达式：{expr}'.format(expr=expr))
        result = jsonpath.jsonpath(obj, expr)
        if result is False:
            # jsonpath没有匹配到数据
            result = None
            logger.info(f'提取失败：提取表达式：{expr}，没有提取到对应的值')
        elif isinstance(result, list):
            if len(result) == 1:
                result = result[0]
            logger.info(f'输出变量，提取表达式：{expr}，提取结果：{result}')
        return result

    @staticmethod
    def extract_value_by_regexp(obj: str = None, expr: str = None):
        """
        根据正则表达从obj中提取相应的值
        Args:
            obj:
            expr: 正则表达式

        Returns:

        """
        return re.findall(pattern=expr, string=obj)

    @staticmethod
    def update_result_dict(extractor: str, variable_name: str, variable_value: (object, list), result_dict: dict):
        if extractor == 'JSONPATH':
            if variable_name.find(':') != -1:
                # variable_name中包含冒号 :
                temp_key_name = variable_name.split(':')[0]
                temp_value_name = variable_name.split(':')[1]
                if temp_value_name.find(',') != -1:
                    temp_value_name_list = temp_value_name.split(',')
                    if not isinstance(variable_value, list):
                        variable_value = [variable_value]
                    result_dict.update({temp_key_name: dict(zip(temp_value_name_list, variable_value))})
                else:
                    result_dict.update({temp_key_name: {temp_value_name: variable_value}})
            else:
                if variable_name.find(',') != -1:
                    temp_value_name_list = variable_name.split(',')
                    if not isinstance(variable_value, list):
                        variable_value = [variable_value]
                    result_dict.update(dict(zip(temp_value_name_list, variable_value)))
                else:
                    result_dict.update({variable_name: variable_value})
        elif extractor == 'REGEXP':
            # TODO 此方式代码设计有所不妥，待后续重新设计
            if variable_name.find(':') != -1:
                # variable_name中包含冒号 :
                temp_key_name = variable_name.split(':')[0]
                temp_value_name = variable_name.split(':')[1]
                if temp_value_name.find(',') != -1:
                    temp_value_name_list = temp_value_name.split(',')
                    temp_variable_value_list = []
                    for item in variable_value:
                        if isinstance(item, str):
                            temp_variable_value_list.append(dict(zip(temp_value_name_list, [item])))
                        elif isinstance(item, tuple):
                            temp_variable_value_list.append(dict(zip(temp_value_name_list, list(item))))
                else:
                    result_dict.update({temp_key_name: [{temp_value_name: item} for item in variable_value]})
            else:
                if variable_name.find(',') != -1:
                    temp_value_name_list = variable_name.split(',')
                    for item in variable_value:
                        if isinstance(item, str):
                            result_dict.update(dict(zip(temp_value_name_list, [item])))
                        elif isinstance(item, tuple):
                            result_dict.update(dict(zip(temp_value_name_list, list(item))))
                else:
                    result_dict.update({variable_name: variable_value})


if __name__ == '__main__':
    obj = json.dumps(
        {"producerGroup": "irs-yingzheng", "topic": "ORDER_STATE_CHANGED", "tag": "10", "key": "KEYTP1661910809164",
         "messageBody": "{\"orderBo\": {\"id\": 1661910809164, \"code\": \"TP1661910809164\", \"scenes\": 10, \"scenesCode\": \"PURCHASE_ORDER\", \"state\": 90, \"placeTime\": \"2022-09-24 11:37:39\"}, \"buyerBo\": {\"buyerOrgId\": 4082002}, \"sellerBoList\": [{\"sellerId\": -1}], \"rebateModelList\": [{\"orderId\": 1661910809164, \"sceneCode\": \"PURCHASE_ORDER\", \"state\": 90, \"placeTime\": \"2022-09-24 11:37:39\", \"orderCode\": \"TP1661910809164\", \"uniqueId\": \"1661910892039\", \"skuList\": [{\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 12800, \"skuId\": 3481, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fakee5qk9vunq0kqb6cz\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 15800, \"skuId\": 3478, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fakevvj7654qbr2oi0wk\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 17800, \"skuId\": 3475, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fakeodotywux6fy5hk50\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 21800, \"skuId\": 3472, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fakemkhvfjm9lecm7uyf\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 33800, \"skuId\": 3484, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fakecufj1535fchylxdq\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 50800, \"skuId\": 3655, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fake8sgvbrc3btl79o8d\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 76800, \"skuId\": 3487, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fakesxcop61p6hylrzsk\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 151800, \"skuId\": 3853, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fakexg2ec3iwbwf1gkkj\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 11800, \"skuId\": 5199, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fake48atzllawesmvqgz\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 14800, \"skuId\": 5200, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fake5w7s5iolp00rn32p\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 16800, \"skuId\": 5197, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fakezlpjx9hn9qa0es1y\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 20800, \"skuId\": 5198, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fakepu3tigh61wca99yg\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 26800, \"skuId\": 5317, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fakegd0y9hqqdnke1s2w\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 32800, \"skuId\": 5196, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fake8ba0yomvcroeingz\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 39800, \"skuId\": 5318, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fakenrzhep0ekifybvqz\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 48800, \"skuId\": 5195, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fakep1bgkss1izovk8zi\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 71800, \"skuId\": 5202, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fakehoijjbj3z7jvtfil\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 141800, \"skuId\": 5201, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fakea8xlsq1bi9ns1vux\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 13800, \"skuId\": 5886, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fake5hr5i0apkglxn5ev\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 19800, \"skuId\": 5885, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fakeo8o5uno2w78zyutn\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 31800, \"skuId\": 5884, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fake46fkdjovrvmrn914\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 46800, \"skuId\": 5889, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fakerz3z9z87gy5tju86\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 66800, \"skuId\": 5888, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fakej8x9x4ptevvih2dy\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 131800, \"skuId\": 5887, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fakeyx3g7nbdv4wsv4z4\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 16000, \"skuId\": 249621, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fakev4gfkql1dt63r7me\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 25800, \"skuId\": 251615, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fake5xhv124mjjapsin3\"}]}, {\"currentQty\": 1, \"mixContractId\": \"\", \"qty\": 1, \"salePrice\": 11000, \"skuId\": 251617, \"type\": \"PURCHASE\", \"codeInfoList\": [{\"realSellCode\": \"http://wine.test.tanjiu.cn/t/?h=fakezd9xldt5yosapk3r\"}]}]}], \"version\": \"V2\"}"},
        ensure_ascii=False)
    expr = r'salePrice\\": (\d+), \\"skuId\\": (\d+)'
    result = Extractor.extract_value_by_regexp(obj, expr)
    print(result)
